class CycleBuffer {
    /**
     * @param {number} capacity
     */
    constructor(capacity) {
        this.cache = new Uint8Array(capacity);
        this.iread = 0;
        this.iwrite = 0;
    }

    /**
     * @param {number} b
     */
    write(b) {
        this.cache[this.iwrite] = b;
        this.iwrite = (this.iwrite + 1) % this.cache.byteLength;
    }

    /**
     * @param {Buffer} buf
     */
    writeBuffer(buf) {
        for (let i = 0; i < buf.length; i++) {
            this.write(buf[i]);
        }
    }

    /**
     * @param {number} n 
     * @param {number} [nskip] 
     * @returns {Buffer}
     */
    readBuffer(n, nskip) {
        let buf = Buffer.alloc(n);
        if (nskip) {
            this.skip(nskip);
        }
        for (let i = 0; i < n; i++) {
            buf[i] = this.read();
        }
        return buf;
    }

    /**
     * @returns {number}
     */
    read() {
        let b = this.cache[this.iread];
        this.iread = (this.iread + 1) % this.cache.byteLength;
        return b;
    }

    /**
     * @param {number} i
     * @returns {number}
     */
    get(i) {
        return this.cache[(this.iread + i) % this.cache.byteLength];
    }

    /**
     * @param {number} n 
     */
    skip(n) {
        this.iread = (this.iread + n) % this.cache.byteLength;
    }

    clear() {
        this.iread = this.iwrite = 0;
    }

    /**
     * @returns {number}
     */
    length() {
        return (this.iwrite + this.cache.byteLength - this.iread) % this.cache.byteLength;
    }
};

module.exports = CycleBuffer;
